using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;


namespace SkinableFormsLib
{
	public class LWLabelDistorted : LWLabel 
	{

		public LWLabelDistorted()
		{
			this.AutoSize = false;
			this.AutoEllipsis = false;
			//this.TextAlign = ContentAlignment.BottomRight;

		}





		private void DesignRedraw()
		{
			//force redraw: shitty
			this.Text = (string)this.Text.Substring(0);
		}


		protected override void OnTextAlignChanged(EventArgs e)
		{
			base.OnTextAlignChanged(e);
			InitStringPath();
			InitStringShadowPath();
			if (DesignMode) DesignRedraw();
		}
		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);
			if (DesignMode) DesignRedraw();
		}

		private float _lwDistortParam1 = 200;
		public float LWDistortParam1
		{
			get { return _lwDistortParam1; }
			set
			{
				_lwDistortParam1 = value;
				InitStringPath();
				InitStringShadowPath();
				if (DesignMode) DesignRedraw();
			}
		}

		private float _lwDistortParam2 = 100;
		public float LWDistortParam2
		{
			get { return _lwDistortParam2; }
			set
			{
				_lwDistortParam2 = value;
				InitStringPath();
				InitStringShadowPath();
				if (DesignMode) DesignRedraw();
			}
		}

		private Point _lwDistortCenter = Point.Empty;
		public Point LWDistortCenter
		{
			get { return _lwDistortCenter; }
			set
			{
				_lwDistortCenter = value;
				InitStringPath();
				InitStringShadowPath();
				if (DesignMode) DesignRedraw();
			}
		}
		private bool _lwNoCLip = true;

		public bool LWNoCLip
		{
			get { return _lwNoCLip; }
			set
			{
				_lwNoCLip = value;

				if (DesignMode) DesignRedraw();
			}
		}












		private float PSQDist(PointF p1, PointF p2)
		{
			float dx = p1.X - p2.X;
			float dy = p1.Y - p2.Y;
			return (float)Math.Sqrt((double)(dx * dx + dy * dy));
		}
		private PointF GetNewPos(PointF p, PointF c)
		{
			float d = _lwDistortParam1 + PSQDist(c, p);
			float nd = (d + 1000 * _lwDistortParam2 / d) / 2;
			PointF ret = PointF.Empty;
			ret.X = c.X + nd * (p.X - c.X) / d;
			ret.Y = c.Y + nd * (p.Y - c.Y) / d;
			return ret;
		}



		

		private RectangleF _lwGetGraphicsPathBounds(ref GraphicsPath gp)
		{

			PointF[] pcts = gp.PathData.Points;

			float mxX = 0.0f;
			float mxY = 0.0f;
			float mnX = 0.0f;
			float mnY = 0.0f;
			for (int i = 0; i < pcts.Length; i++)
			{
				mxX = Math.Max(pcts[i].X, mxX);
				mxY = Math.Max(pcts[i].Y, mxY);
				mnX = Math.Min(pcts[i].X, mnX);
				mnY = Math.Min(pcts[i].Y, mnY);
			}


			return new RectangleF(mnX, mnY, mxX - mnX, mxY - mnY);
		}

		private SizeF _lwGetShiftByTextAlign(ref GraphicsPath gp, ContentAlignment alignment)
		{

			RectangleF bb = _lwGetGraphicsPathBounds(ref gp);
			float nx = (_lwRectangle.Width - bb.Width) / 2;
			float ny = (_lwRectangle.Height - bb.Height) / 2;
			float nnx = _lwRectangle.Width - bb.Width;
			float nny = _lwRectangle.Height - bb.Height;

			SizeF tr = SizeF.Empty;
			switch (alignment)
			{
				case ContentAlignment.MiddleCenter:
					tr.Width = nx;
					tr.Height = ny;
					break;
				case ContentAlignment.MiddleLeft:
					tr.Height = ny;
					break;
				case ContentAlignment.MiddleRight:
					tr.Width = nnx;
					tr.Height = ny;
					break;

				case ContentAlignment.BottomCenter:
					tr.Width = nx;
					tr.Height = nny;
					break;
				case ContentAlignment.BottomLeft:
					tr.Height = nny;
					break;
				case ContentAlignment.BottomRight:
					tr.Width = nnx;
					tr.Height = nny;
					break;
				case ContentAlignment.TopCenter:
					tr.Width = nx;
					break;
				case ContentAlignment.TopLeft:
					break;
				case ContentAlignment.TopRight:
					tr.Width = nny;
					break;
			}


			return tr;

		}

		private void _lwCreateStringPath(ref GraphicsPath _srcPath, ref GraphicsPath _dstPath, ref SizeF _pathShift, bool _distort)
		{
			PointF[] pcts = _srcPath.PathData.Points;
			PointF pp = PointF.Empty;
			if (pcts.Length > 0)
			{
				pp = GetNewPos(pcts[0], _lwDistortCenter);
			}
			byte[] typs = _srcPath.PathData.Types;

			for (int i = 0; i < pcts.Length; i++)
			{
				PointF p0 = PointF.Add(pcts[i], _pathShift);
				//PointF p0 = pcts[i];
				PointF p = p0;
				if (_distort)
				{
					p = GetNewPos(p0, _lwDistortCenter);
				}

				byte pt = typs[i];

				bool Line = (((byte)PathPointType.Line) & pt) > 0;
				bool CloseSubpath = (((byte)PathPointType.CloseSubpath) & pt) > 0;
				bool Bezier = (((byte)PathPointType.Bezier) & pt) > 0;
				bool Start = (pt == 0);// (((byte)PathPointType.Start) & pt) > 0;
				bool PathMarker = (((byte)PathPointType.PathMarker) & pt) > 0;

				if (Start)
				{
					_dstPath.StartFigure();
				}
				if (Line)
				{
					_dstPath.AddLine(pp, p);
				}
				if (CloseSubpath)
				{
					_dstPath.CloseFigure();
				}

				pp = p;
			}

			_dstPath.Flatten();
		}

		private void CustomStringPath(ref GraphicsPath _strPath)
		{

			GraphicsPath _tempPath1 = new GraphicsPath();
			GraphicsPath _tempPath2 = new GraphicsPath();
			_tempPath1.AddString(this.Text, Font.FontFamily, (int)Font.Style, Font.Size * ((float)4 / 3.1f), new Point(-6, -2), StringFormat.GenericDefault);
			_tempPath1.Flatten();
			_strPath = new GraphicsPath();
			SizeF tr = _lwGetShiftByTextAlign(ref _tempPath1, TextAlign);
			_lwCreateStringPath(ref _tempPath1, ref _tempPath2, ref tr, true);
			if (_lwNoCLip)
			{
				GraphicsPath _tempPath3 = new GraphicsPath();
				SizeF tr2 = _lwGetShiftByTextAlign(ref _tempPath2, TextAlign);
				_lwCreateStringPath(ref _tempPath2, ref _tempPath3, ref tr2, false);
				_strPath = (GraphicsPath)_tempPath3.Clone();
				_tempPath3.Dispose();
			}
			else
			{
				_strPath = (GraphicsPath)_tempPath2.Clone();
			}
			_tempPath1.Dispose();
			_tempPath2.Dispose();
		}

		internal override void InitStringPath()
		{
			CustomStringPath(ref _stringPath);
		}



		private Matrix _lwShadowShiftMatrix = new Matrix();

		internal override void InitStringShadowPath()
		{
			_stringShadowPath = new GraphicsPath();
			CustomStringPath(ref _stringShadowPath);
			_lwShadowShiftMatrix.Reset();
			_lwShadowShiftMatrix.Translate(_lwShadowShift.X, _lwShadowShift.Y);
			_stringShadowPath.Transform(_lwShadowShiftMatrix);

		}








	}
}
